package com.ruoyi.order.controller;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.ruoyi.businessOrder.domain.BusinessOrder;
import com.ruoyi.businessOrder.domain.dto.RefundApplyDto;
import com.ruoyi.businessOrder.domain.dto.RefundAuditDto;
import com.ruoyi.common.config.WxPaymentConfig;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.common.utils.WechatPay2ValidatorForRequest;
import com.ruoyi.order.domain.OrderCreateDTO;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.order.domain.Order;
import com.ruoyi.order.service.IOrderService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;

/**
 * 订单信息Controller
 *
 * @author ruoyi
 * @date 2025-06-03
 */
@RestController
@RequestMapping("/ruoyi/order")
@Slf4j
public class OrderController extends BaseController
{
    @Autowired
    private IOrderService orderService;

    @Autowired
    private WxPaymentConfig wxPaymentConfig;

    /**
     * 获取订单列表时，将订单状态为'3'（退款中）的优先级设为最高，排在最前面
     * 获取交易订单汇总列表
     */
    @GetMapping("/selectOrderSummaryList")
    public TableDataInfo selectOrderSummaryList(Order order) {
        startPage();
        List<Order> list = orderService.selectOrderSummaryList(order);
        return getDataTable(list);
    }


    /**
     * 微信支付分账
     */
    @ApiOperation("微信支付分账")
    @PostMapping("/profitSharing/{orderId}")
    public AjaxResult profitSharing(@PathVariable("orderId") Long orderId) {
        try {
            Map<String, Object> result = orderService.profitSharing(orderId);
            if ((Boolean) result.get("success")) {
                return AjaxResult.success("分账成功", result);
            } else {
                return AjaxResult.error("分账失败：" + result.get("errorMsg"));
            }
        } catch (Exception e) {
            log.error("分账处理异常，订单ID: {}", orderId, e);
            return AjaxResult.error("分账处理异常：" + e.getMessage());
        }
    }


    /**
     * 查询订单信息列表
     */
//    @PreAuthorize("@ss.hasPermi('ruoyi:order:list')")
    @GetMapping("/list")
    public TableDataInfo list(Order order)
    {
        startPage();
        List<Order> list = orderService.selectOrderList(order);
        return getDataTable(list);
    }

    /**
     * 导出订单信息列表
     */
//    @PreAuthorize("@ss.hasPermi('ruoyi:order:export')")
    @Log(title = "订单信息", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, Order order)
    {
        List<Order> list = orderService.selectOrderList(order);
        ExcelUtil<Order> util = new ExcelUtil<Order>(Order.class);
        util.exportExcel(response, list, "订单信息数据");
    }

    /**
     * 获取订单信息详细信息
     */
//    @PreAuthorize("@ss.hasPermi('ruoyi:order:query')")
    @GetMapping(value = "/{orderId}")
    public AjaxResult getInfo(@PathVariable("orderId") Long orderId)
    {
        return success(orderService.selectOrderByOrderId(orderId));
    }

    /**
     * 新增订单信息
     */
//    @PreAuthorize("@ss.hasPermi('ruoyi:order:add')")
    @Log(title = "订单信息", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody Order order)
    {
        order.setOrderCode(IdUtils.generateOrderCode());
        return toAjax(orderService.insertOrder(order));
    }


    /**
     * 创建完整订单（含商品详情）
     */
//    @PreAuthorize("@ss.hasPermi('ruoyi:order:add')")
    @Log(title = "订单信息", businessType = BusinessType.INSERT)
    @PostMapping("/createFullOrder")
    public AjaxResult createFullOrder(@RequestBody OrderCreateDTO createDTO) {
        // 获取创建的订单对象
        Order createdOrder = orderService.createFullOrder(createDTO);

        // 创建返回数据（只包含前端需要的关键信息）
        Map<String, Object> result = new HashMap<>();
        result.put("orderId", createdOrder.getOrderId());
        result.put("orderCode", createdOrder.getOrderCode());
        result.put("totalAmount", createdOrder.getTotalAmount());
        result.put("masterStatus", createdOrder.getMasterStatus());
        result.put("payTime", createdOrder.getPayTime());
        result.put("createTime", createdOrder.getCreateTime());

        // 返回成功响应，包含订单信息
        return AjaxResult.success("订单创建成功", result);
    }


    /**
     * 修改订单信息
     */
    @PreAuthorize("@ss.hasPermi('ruoyi:order:edit')")
    @Log(title = "订单信息", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody Order order)
    {
        return toAjax(orderService.updateOrder(order));
    }

    /**
     * 删除订单信息
     */
    @PreAuthorize("@ss.hasPermi('ruoyi:order:remove')")
    @Log(title = "订单信息", businessType = BusinessType.DELETE)
	@DeleteMapping("/{orderIds}")
    public AjaxResult remove(@PathVariable Long[] orderIds)
    {
        return toAjax(orderService.deleteOrderByOrderIds(orderIds));
    }

    // ==================== 微信支付相关接口 ====================
    /**
     * 微信支付回调通知
     * 注意：此接口必须为公网可访问，且支持HTTPS
     */
    @PostMapping("/miniAppNotify")
    @ApiOperation("微信支付回调通知")
    public ResponseEntity<Map<String, Object>> miniAppNotify(HttpServletRequest request,
                                                             HttpServletResponse response,
                                                             @RequestBody String requestBody) {
        // 正确实现了微信支付回调处理
        log.info("微信支付回调开始");
        try {
            log.info("收到微信支付回调通知，请求体长度: {}", requestBody.length());

            // 1. 验证签名（防止重放攻击和篡改）
            // 解析回调数据获取requestId
            JSONObject notifyData = com.alibaba.fastjson2.JSON.parseObject(requestBody);
            String requestId = notifyData.getString("id");
            if (requestId == null) {
                log.error("微信支付回调缺少requestId");
                return ResponseEntity.badRequest().body(buildFailResponse("缺少请求ID"));
            }

            // 使用专门的HttpServletRequest验证器
            WechatPay2ValidatorForRequest validator = new WechatPay2ValidatorForRequest(
                wxPaymentConfig.getWechatPayVerifier(), requestId, requestBody
            );
            if (!validator.validate(request)) {
                log.error("微信支付回调签名验证失败，可能为非法请求");
                return ResponseEntity.badRequest().body(buildFailResponse("签名验证失败"));
            }

            // 2. 解析回调数据（已在上一步解析过requestId）
            String eventType = notifyData.getString("event_type");
            String resourceType = notifyData.getString("resource_type");

            log.info("微信支付回调事件类型: {}, 资源类型: {}", eventType, resourceType);

            // 3. 只处理支付成功事件
            if (!"TRANSACTION.SUCCESS".equals(eventType)) {
                log.info("忽略非支付成功事件: {}", eventType);
                return ResponseEntity.ok(buildSuccessResponse());
            }

            // 4. 验证资源类型
            if (!"encrypt-resource".equals(resourceType)) {
                log.error("不支持的资源类型: {}", resourceType);
                return ResponseEntity.badRequest().body(buildFailResponse("不支持的资源类型"));
            }

            // 5. 解密resource数据
            JSONObject resource = notifyData.getJSONObject("resource");
            String ciphertext = resource.getString("ciphertext");
            String associatedData = resource.getString("associated_data");
            String nonceStr = resource.getString("nonce");

            // 解密数据
            String decryptData = decryptCallbackData(ciphertext, associatedData, nonceStr);
            JSONObject paymentData = com.alibaba.fastjson2.JSON.parseObject(decryptData);

            log.info("支付成功回调解密数据: {}", paymentData.toJSONString());

            // 6. 处理业务逻辑
            boolean processResult = processPaymentSuccess(paymentData);

            if (processResult) {
                log.info("微信支付回调处理成功");
                return ResponseEntity.ok(buildSuccessResponse());
            } else {
                log.error("处理支付成功业务逻辑失败");
                // 返回失败，微信支付会重试
                return ResponseEntity.badRequest().body(buildFailResponse("业务处理失败"));
            }

        } catch (Exception e) {
            log.error("处理微信支付回调异常", e);
            // 返回失败，微信支付会重试
            return ResponseEntity.badRequest().body(buildFailResponse("处理回调异常"));
        }
    }

    /**
     * 解密回调数据
     */
    private String decryptCallbackData(String ciphertext, String associatedData, String nonce)
            throws Exception {
        try {
            AesUtil aesUtil = new AesUtil(wxPaymentConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
            return aesUtil.decryptToString(
                    associatedData.getBytes(StandardCharsets.UTF_8),
                    nonce.getBytes(StandardCharsets.UTF_8),
                    ciphertext
            );
        } catch (Exception e) {
            log.error("解密微信支付回调数据失败", e);
            throw new RuntimeException("解密失败", e);
        }
    }

    /**
     * 处理支付成功业务逻辑
     */
    private boolean processPaymentSuccess(JSONObject paymentData) {
        try {
            String outTradeNo = paymentData.getString("out_trade_no");
            String transactionId = paymentData.getString("transaction_id");
            String tradeState = paymentData.getString("trade_state");
            String successTime = paymentData.getString("success_time");

            log.info("支付成功回调参数: outTradeNo={}, transactionId={}, tradeState={}, successTime={}",
                    outTradeNo, transactionId, tradeState, successTime);

            if (!"SUCCESS".equals(tradeState)) {
                log.warn("交易状态非成功: {}", tradeState);
                return false;
            }

            // 更新订单状态
            return orderService.updateOrderStatus(outTradeNo, transactionId, successTime);

        } catch (Exception e) {
            log.error("处理支付成功业务异常", e);
            return false;
        }
    }

    /**
     * 构建成功响应
     */
    private Map<String, Object> buildSuccessResponse() {
        Map<String, Object> response = new HashMap<>();
        response.put("code", "SUCCESS");
        response.put("message", "成功");
        return response;
    }

    /**
     * 构建失败响应
     */
    private Map<String, Object> buildFailResponse(String message) {
        Map<String, Object> response = new HashMap<>();
        response.put("code", "FAIL");
        response.put("message", message);
        return response;
    }


    /**
     * 调用统一下单API,获取预支付ID
     */
    @ApiOperation("统一下单测试接口")
    @PostMapping("/jsapi/{orderId}")
    public AjaxResult miniAppGetPrePayId(@PathVariable("orderId") Long orderId) throws Exception {
        log.info("发起支付请求");
        // 返回预支付ID
        HashMap<String, Object> map = orderService.miniAppGetPrePayId(orderId);

        return success(map);
    }

    /**
     * 通过JSAPI/小程序下单接口获取到发起支付的必要参数prepay_id,构造签名
     */
    @ApiOperation("JSAPI/小程序下单接口")
    @PostMapping("/getWxpayParams")
    public AjaxResult getWxpayParams(@RequestBody Map<String, Object> params) throws Exception {
        try {
            // 1. 解析并校验 orderId
            Object orderIdObj = params.get("orderId");
            if (orderIdObj == null) {
                return AjaxResult.error("参数缺失（orderId必须为数字）");
            }
            Long orderId;

            try {
                if (orderIdObj instanceof Number) {
                    orderId = ((Number) orderIdObj).longValue();
                } else {
                    orderId = Long.valueOf(orderIdObj.toString());
                }
            } catch (NumberFormatException e) {
                return AjaxResult.error("orderId必须为数字");
            }

            // 订单id
//            Long orderId = (Long) params.get("orderId");
            // 订单号
            String orderNo = (String) params.get("orderNo");
            // 微信openId
            String openId = (String) params.get("openId");

            Integer totalFee;
            try {
                // 将金额字符串转换为BigDecimal
                BigDecimal amount = new BigDecimal(params.get("totalFee").toString());

                // 验证金额有效性
                if (amount.compareTo(BigDecimal.ZERO) <= 0) {
                    return AjaxResult.error("支付金额必须大于0");
                }
                // 元转分（乘以100后取整）
                totalFee = amount.multiply(new BigDecimal("100")).intValueExact();

            } catch (NumberFormatException | ArithmeticException e) {
                return AjaxResult.error("支付金额格式错误，示例：0.01");
            } catch (NullPointerException e) {
                return AjaxResult.error("未提供支付金额");
            }

            // 2. 校验参数完整性
            if (orderId == null || orderNo == null || totalFee == null || openId == null) {
                return AjaxResult.error("参数缺失（orderId、orderNo、totalFee、openId均为必填）");
            }

            Map<String, String> payParams = orderService.getWxpayParams(orderId, orderNo, totalFee, openId);

            // 4. 返回成功结果（包含支付参数）
            return AjaxResult.success("获取支付参数成功", payParams);

        } catch (Exception e) {
            // 5. 返回失败结果（包含错误信息）
            return AjaxResult.error("获取支付参数失败：" + e.getMessage());
        }

    }

    /**
     * 关闭订单
     */
    @ApiOperation("关闭订单")
    @PostMapping("/miniAppCloseOrder/{orderId}")
    public AjaxResult miniAppCloseOrder(@PathVariable("orderId") Long orderId) throws Exception {
        log.info("关闭订单");
        // 返回预支付ID
        HashMap<String, Object> map = orderService.miniAppCloseOrder(orderId);

        return success(map);
    }

    /**
     * 提交退款申请（用户端）
     */
    @ApiOperation("提交退款申请")
    @PostMapping("/submitRefundApply")
    public AjaxResult submitRefundApply(@RequestBody RefundApplyDto refundApplyDto) {
        try {
            orderService.applyRefund(refundApplyDto);
            return AjaxResult.success("退款申请已提交，等待管理员审核");
        } catch (ServiceException e) {
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
            log.error("提交退款申请失败", e);
            return AjaxResult.error("系统异常，请稍后重试");
        }
    }

    /**
     * 审核退款申请（管理端）
     */
    @ApiOperation("审核退款申请")
//    @PreAuthorize("@ss.hasPermi('refund:application:audit')")
    @PutMapping("/auditRefundApplication/{refundId}")
    public AjaxResult auditRefundApplication(
            @PathVariable("refundId") Long refundId,
            @RequestBody RefundAuditDto auditDto) {
        try {
            // 验证审核状态是否合法
            if (!"1".equals(auditDto.getAuditStatus()) && !"2".equals(auditDto.getAuditStatus())) {
                return AjaxResult.error("审核状态不合法");
            }

            orderService.auditRefundApplication(refundId, auditDto);
            return AjaxResult.success("审核操作成功");
        } catch (ServiceException e) {
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
            log.error("审核退款申请失败", e);
            return AjaxResult.error("系统异常，请稍后重试");
        }
    }

    /**
     * 退款申请
     */
    @ApiOperation("退款申请")
    @PostMapping("/miniAppRefund/{orderId}/{reason}")
    public AjaxResult miniAppRefund(@PathVariable("orderId") Long orderId,
                                    @PathVariable("reason") String reason) throws Exception{
        log.info("退款申请");
        try {
            HashMap<String, Object> map = orderService.miniAppRefund(orderId,  reason);
            return AjaxResult.success("退款申请成功", map);
        } catch (ServiceException e) {
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
            log.error("退款处理异常", e);
            return AjaxResult.error("系统异常，请稍后重试");
        }
    }

    /**
     * 根据顾客id和商品订单状态获取交易订单列表
     */
    // @PreAuthorize("@ss.hasPermi('ruoyi:businessOrder:query')")
    @GetMapping("/guest/orderStatus/{guestId}")
    public AjaxResult getByGuestIdAndOrderStatus(
            @PathVariable("guestId") Long guestId,
            @RequestParam(value = "orderStatus", required = false) String orderStatus)
    {
        List<Order> orders = orderService.selectOrderByGuestIdAndOrderStatus(guestId, orderStatus);
        return success(orders);
    }

    /**
     * 根据顾客id和商品订单状态获取交易订单列表（分页）
     */
    // @PreAuthorize("@ss.hasPermi('ruoyi:businessOrder:query')")
    @GetMapping("/guest/masterStatus/{guestId}")
    public TableDataInfo getByGuestIdAndOrderStatusWithPagination(
            @PathVariable("guestId") Long guestId,
            @RequestParam(value = "masterStatus", required = false) String masterStatus,
            @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {

        // 计算偏移量
        int offset = (pageNum - 1) * pageSize;

        // 查询订单列表
        List<Order> orders = orderService.selectOrderByGuestIdAndOrderStatusWithPagination(guestId, masterStatus, pageNum, pageSize);

        // 查询总数
        int total = orderService.countOrderByGuestIdAndOrderStatus(guestId, masterStatus);

        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(200);
        rspData.setMsg("查询成功");
        rspData.setRows(orders);
        rspData.setTotal(total);
        return rspData;
    }


    /**
     * 根据订单id获取订单详情
     */
    @GetMapping(value = "/getOrderInfo/{orderId}")
    public AjaxResult getOrderInfo(@PathVariable("orderId") Long orderId) {
        // 使用包含商品详情的方法
        Order order = orderService.selectOrderByOrderIdWithDetails(orderId);
        return success(order);
    }

    /**
     * 查询订单支付状态
     *
     * @param orderNo 订单号
     * @return 订单支付状态
     */
    @GetMapping("/payment/status/{orderNo}")
    public AjaxResult checkOrderPaymentStatus(@PathVariable("orderNo") String orderNo) {
        try {
            String paymentStatus = orderService.checkOrderPaymentStatus(orderNo);
            Map<String, Object> result = new HashMap<>();
            result.put("orderNo", orderNo);
            result.put("payStatus", paymentStatus);
            return AjaxResult.success("查询成功", result);
        } catch (ServiceException e) {
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
            log.error("查询订单支付状态异常", e);
            return AjaxResult.error("系统异常，请稍后重试");
        }
    }

    /**
     * 获取订单核销码信息
     *
     * @param orderId 订单ID
     * @return 核销码信息
     */
    @GetMapping("/verification/{orderId}")
    public AjaxResult getOrderVerificationInfo(@PathVariable("orderId") Long orderId) {
        try {
            Order order = orderService.selectOrderByOrderId(orderId);
            if (order == null) {
                return AjaxResult.error("订单不存在");
            }

            // 检查订单是否已支付
            if (!"1".equals(order.getMasterStatus())) {
                return AjaxResult.error("只有已支付的订单才能获取核销码");
            }

            Map<String, Object> result = new HashMap<>();
            result.put("orderId", order.getOrderId());
            result.put("orderCode", order.getOrderCode());
            result.put("verificationCode", order.getVerificationCode());
            result.put("verificationStatus", order.getVerificationStatus());
            result.put("verificationTime", order.getVerificationTime());
            result.put("goodsDetails", order.getGoodsDetails());

            return AjaxResult.success("获取成功", result);
        } catch (Exception e) {
            log.error("获取订单核销信息异常", e);
            return AjaxResult.error("系统异常，请稍后重试");
        }
    }

    /**
     * 检查订单核销状态
     *
     * @param verificationCode 核销码
     * @return 核销状态
     */
    @GetMapping("/verification/status/{verificationCode}")
    public AjaxResult checkVerificationStatus(@PathVariable("verificationCode") String verificationCode) {
        try {
            Order order = orderService.selectOrderByVerificationCode(verificationCode);
            if (order == null) {
                return AjaxResult.error("未找到对应的订单");
            }

            Map<String, Object> result = new HashMap<>();
            result.put("orderId", order.getOrderId());
            result.put("orderCode", order.getOrderCode());
            result.put("verificationStatus", order.getVerificationStatus());
            result.put("verificationTime", order.getVerificationTime());

            return AjaxResult.success("查询成功", result);
        } catch (Exception e) {
            log.error("查询核销状态异常", e);
            return AjaxResult.error("系统异常，请稍后重试");
        }
    }

    /**
     * 生成并返回订单核销二维码图片
     */
    @GetMapping("/verification/qrcode/{orderId}")
    public void generateVerificationQRCode(@PathVariable("orderId") Long orderId, HttpServletResponse response) {
        try {
            // 1. 获取订单信息
            Order order = orderService.selectOrderByOrderId(orderId);
            if (order == null) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "订单不存在");
                return;
            }

            // 2. 检查订单状态
            if (!"1".equals(order.getMasterStatus())) {
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "订单未支付或状态异常");
                return;
            }

            // 3. 获取核销码
            String verificationCode = order.getVerificationCode();
            if (StringUtils.isEmpty(verificationCode)) {
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "订单无有效核销码");
                return;
            }

            // 4. 生成QR码图片
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(verificationCode, BarcodeFormat.QR_CODE, 300, 300);

            // 5. 输出图片到响应流
            response.setContentType("image/png");
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream());
            response.getOutputStream().flush();

        } catch (Exception e) {
            log.error("生成核销二维码失败", e);
            try {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "生成二维码失败");
            } catch (IOException ioException) {
                log.error("无法发送错误响应", ioException);
            }
        }
    }

}
